#pragma once

#include <vector>
#include "Details.hpp"
#include "Fields.hpp"
#include "AbstractLayer.hpp"

namespace rpc
{
    using Address = std::pair<std::string, int>; // (ip, port)

    class JsonMessage : public BaseMessage
    {
    public:
        // using ptr = std::make_shared<rpc::JsonMessage>(); // 真蠢！
        using ptr = std::shared_ptr<rpc::JsonMessage>;

        virtual std::string serialize() override
        {
            std::string body;
            bool n = JSON::Serialize(_body, body);
            if (n == false)
                return std::string();
            return body;
        }

        virtual bool unserialize(const std::string &msg) override
        {
            return JSON::Unserialize(_body, msg);
        }

    protected:
        Json::Value _body;
    };

    class JsonRequest : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonRequest>;
    };

    class JsonResponse : public JsonMessage
    {
    public:
        using ptr = std::shared_ptr<JsonResponse>;

        virtual bool check() override
        {
            // 检查 rcode
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                ELOG("rcode not exit, or type wrong");
                return false;
            }
            return true;
        }

        virtual RCODE rcode()
        {
            return (RCODE)_body[KEY_RCODE].asInt();
        }

        virtual void setRcode(RCODE rcode)
        {
            _body[KEY_RCODE] = (int)rcode;
        }
    };

    class RpcRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<RpcRequest>;
        virtual bool check() override
        {
            // 检查请求方法 请求参数
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                ELOG("rpc_request method not exit, or type wrong");
                return false;
            }
            if (_body[KEY_PARAMS].isNull() == true || _body[KEY_PARAMS].isObject() == false)
            {
                ELOG("rpc_request params not exit, or type wrong");
                return false;
            }
            return true;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setMethod(std::string method)
        {
            _body[KEY_METHOD] = method;
        }

        Json::Value params()
        {
            return _body[KEY_PARAMS];
        }

        void setParams(Json::Value params)
        {
            _body[KEY_PARAMS] = params;
        }
    };
    // 请求 有状态码 吗？rcode -- response code
    // if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
    // {
    //     ELOG("rcode not exit, or type wrong");
    //     return false;
    // }

    class TopicRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<TopicRequest>;
        virtual bool check() override
        {
            // 检查请求主题类型 请求主题操作 请求主题参数
            if (_body[KEY_TOPIC_NAME].isNull() == true || _body[KEY_TOPIC_NAME].isString() == false)
            {
                ELOG("topic theme not exit, or type wrong");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("topic option type not exit, or type wrong");
                return false;
            }
            if (_body[KEY_TOPIC_MSG].isNull() == true || _body[KEY_TOPIC_MSG].isString() == false)
            {
                ELOG("topic message not exit, or type wrong");
                return false;
            }
            return true;
        }

        std::string topicTheme()
        {
            return _body[KEY_TOPIC_NAME].asString();
        }
        void setTopicTheme(const std::string &theme)
        {
            _body[KEY_TOPIC_NAME] = theme;
        }

        TOPIC_OP_TYPE topicOption()
        {
            return (TOPIC_OP_TYPE)_body[KEY_OPTYPE].asInt();
        }
        void setTopicOption(TOPIC_OP_TYPE op)
        {
            _body[KEY_OPTYPE] = (int)op;
        }

        std::string topicMsg()
        {
            return _body[KEY_TOPIC_MSG].asString();
        }
        void setTopicMsg(const std::string &msg)
        {
            _body[KEY_TOPIC_MSG] = msg;
        }
    };

    class ServiceRequest : public JsonRequest
    {
    public:
        using ptr = std::shared_ptr<ServiceRequest>;
        virtual bool check() override
        {
            // 检查请求服务方法 主机地址 操作类型
            if (_body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false)
            {
                ELOG("service method not exit, or type wrong");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("service option not exit, or type wrong");
                return false;
            }

            // 服务发现 不需要检查 主机地址信息 <-> 不是服务发现 && 主机地址信息正确
            if (_body[KEY_OPTYPE].asInt() != (int)SERVICE_OP_TYPE::SERVICE_DISCOVERY &&
                (_body[KEY_HOST].isNull() == true || _body[KEY_HOST].isObject() == false ||
                 _body[KEY_HOST][KEY_HOST_IP].isNull() == true || _body[KEY_HOST][KEY_HOST_IP].isString() == false ||
                 _body[KEY_HOST][KEY_HOST_PORT].isNull() == true || _body[KEY_HOST][KEY_HOST_PORT].isIntegral() == false))
            {
                ELOG("host address information error");
                return false;
            }

            return true;
        }

        std::string Method()
        {
            return _body[KEY_METHOD].asString();
        }
        void setMethod(const std::string &method)
        {
            _body[KEY_METHOD] = method;
        }

        SERVICE_OP_TYPE Option()
        {
            return (SERVICE_OP_TYPE)_body[KEY_OPTYPE].asInt();
        }
        void setOption(SERVICE_OP_TYPE op)
        {
            _body[KEY_OPTYPE] = (int)op;
        }

        Address host()
        {
            Address addr;
            addr.first = _body[KEY_HOST][KEY_HOST_IP].asString();
            addr.second = _body[KEY_HOST][KEY_HOST_PORT].asInt();
            return addr;
        }
        void setHost(Address addr)
        {
            // host 是一个对象, 不能这么设置
            // _body[KEY_HOST][KEY_HOST_IP] = addr.first;
            // _body[KEY_HOST][KEY_HOST_PORT] = addr.second;

            Json::Value host;
            host[KEY_HOST_IP] = addr.first;
            host[KEY_HOST_PORT] = addr.second;
            _body[KEY_HOST] = host;
        }
    };

    class RpcResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<RpcResponse>;
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                ELOG("rcode not exit, or type wrong");
                return false;
            }
            if (_body[KEY_RES].isNull() == true)
            {
                ELOG("no rpc_result in the response");
                return false;
            }
            return true;
        }

        Json::Value result()
        {
            return _body[KEY_RES];
        }

        void setResult(Json::Value res)
        {
            _body[KEY_RES] = res;
        }
    };

    class TopicResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<TopicResponse>;
    };

    class ServiceResponse : public JsonResponse
    {
    public:
        using ptr = std::shared_ptr<ServiceResponse>;
        virtual bool check() override
        {
            if (_body[KEY_RCODE].isNull() == true || _body[KEY_RCODE].isIntegral() == false)
            {
                ELOG("rcode not exit, or type wrong");
                return false;
            }
            if (_body[KEY_OPTYPE].isNull() == true || _body[KEY_OPTYPE].isIntegral() == false)
            {
                ELOG("service option not exit, or type wrong");
                return false;
            }
            if (_body[KEY_OPTYPE].asInt() == (int)SERVICE_OP_TYPE::SERVICE_DISCOVERY ||
                _body[KEY_METHOD].isNull() == true || _body[KEY_METHOD].isString() == false ||
                _body[KEY_HOST].isNull() == true || _body[KEY_HOST].isArray() == false)
            {
                ELOG("service discovery response error");
                return false;
            }
            return true;
        }

        SERVICE_OP_TYPE option()
        {
            return (SERVICE_OP_TYPE)_body[KEY_OPTYPE].asInt();
        }

        void setOption(SERVICE_OP_TYPE op)
        {
            _body[KEY_OPTYPE] = (int)op;
        }

        std::string method()
        {
            return _body[KEY_METHOD].asString();
        }

        void setMethod(std::string method)
        {
            _body[KEY_METHOD] = method;
        }

        std::vector<Address> hosts()
        {
            std::vector<Address> addrs;
            int sz = _body[KEY_HOST].size();
            for (int i = 0; i < sz; i++)
            {
                Address addr;
                addr.first = _body[KEY_HOST][i][KEY_HOST_IP].asString();
                addr.second = _body[KEY_HOST][i][KEY_HOST_PORT].asInt();
                addrs.push_back(addr);
            }
            return addrs;
        }

        void setHosts(std::vector<Address> addrs)
        {
            for (auto &addr : addrs)
            {
                Json::Value val;
                val[KEY_HOST_IP] = addr.first;
                val[KEY_HOST_PORT] = addr.second;
                _body[KEY_HOST].append(val);
            }
        }
    };

    // 消息对象生产工厂
    class MessageFactory
    {
    public:
        // 基类指针只能访问基类方法
        static BaseMessage::ptr create(MSG_TYPE type)
        {
            switch (type)
            {
            case MSG_TYPE::REQ_RPC:
                return std::make_shared<RpcRequest>();
            case MSG_TYPE::RSP_RPC:
                return std::make_shared<RpcResponse>();
            case MSG_TYPE::REQ_SERVICE:
                return std::make_shared<ServiceRequest>();
            case MSG_TYPE::RSP_SERVICE:
                return std::make_shared<ServiceResponse>();
            case MSG_TYPE::REQ_TOPIC:
                return std::make_shared<TopicRequest>();
            case MSG_TYPE::RSP_TOPIC:
                return std::make_shared<TopicResponse>();
            }

            // std:make_shared 需要调用默认构造函数来创建对象，要求 BaseMessage 类必须有公共的默认构造函数
            // return std::make_shared<BaseMessage>(); // error

            // BaseMessage::ptr() 是一个静态成员变量，内部已经处理了对象创建的逻辑，不会因为缺少默认构造而报错
            return BaseMessage::ptr();
        }

        // c++11 forward -- 完美转发
        template <class T, class... Args>
        static std::shared_ptr<T> create(Args &&...args)
        {
            return std::make_shared<T>(std::forward<Args>(args)...);
        }
    };
}